import { PositionHelper } from "utils/position/PositionHelper";

 
/*
传输链
*/
export class TransferNode<T extends IRoomPosition=IRoomPosition>
{
    parentNode?:TransferNode<T>;
    childnodes:TransferNode<T>[]=[];

    nextNode?:TransferNode<T>;   // 线索。相邻的叶子节点。但距离更远 离目标点
    
    pos:T;
    state:0|1=0;
    constructor(pos:T,parent?:TransferNode<T>)
    {
        this.pos = pos;
        this.parentNode = parent;
    }
    get posKey()
    {
        return this.pos.x+this.pos.y*50;
    }
    addChild(nodes:TransferNode<T>[])
    {
        this.childnodes.push(...nodes);
    }
}

interface IPosFilter<T extends IRoomPosition>
{
    (pos:T):boolean
}

export class TransferTree<T extends IRoomPosition=IRoomPosition>
{
    private _filter:IPosFilter<T>;
    private _treeRoot!:TransferNode<T>[];

    private moveAction:INodeActionMove<T>[]=[];
    private moveToAction:INodeActionMoveTo<T>[]=[];
    private workPositon:Record<number,TransferNode<T>>={};

    // 根节点下面所有的子节点
    private rootChildrenPositon:Record<number,Record<number,TransferNode<T>>>={};
    constructor()
    {
        this._filter=(pos:T)=>{
            return Game.rooms[pos.roomName].getTerrain().get(pos.x,pos.y) != TERRAIN_MASK_WALL
        }
    }
    // 根节点坐标
    public init(root:T[],cpos:T,deep:number=3,filter?:IPosFilter<T>)
    {
        this.workPositon={}
        this.rootChildrenPositon={}
        const rootNode =_.map(root,e=> new TransferNode<T>(e));
        if(filter)
        {
            this._treeRoot = this.makeTransferTree(rootNode,deep, filter);
        }
        else
        {
            this._treeRoot = this.makeTransferTree(rootNode,deep, this._filter);
        }
        
        for(const e of  this._treeRoot)
        {
            const out:TransferNode<T>[]=[];
            this.getChildren(e,out);
            const workPositon:Record<number,TransferNode<T>>={};
            for(const f of  out)
            {
                workPositon[f.posKey]= f;
            }
            this.makeLeafNodeConnect(e,cpos);
            this.rootChildrenPositon[e.posKey]=workPositon;
        }
    }

    private makeTransferTree(root:TransferNode<T>[],deep:number,filter:IPosFilter<T> )
    {
        const visitlist:Set<number> = new Set<number>();
      
        let NextNode:TransferNode<T>[]= root;
        let deepnum=1;
        while(NextNode.length>0  )
        {
          
            const nextchildren :TransferNode<T>[]=[];
            if(deepnum>deep)
            {
                break;
            }
            for(const e of NextNode)
            {
                const childNode = this.findChildNode(e,visitlist,filter,deepnum==1?8:2);
                for(const e of childNode)
                {
                    visitlist.add(e.posKey);
                }
                nextchildren.push(...childNode);
            }
            deepnum++;
            NextNode = nextchildren;
        }
       
        return root;
    }
    /**
     * 叶子节点建立连接
     * @param root 跟节点
     * @param controllerp 叶子节点朝向的控制器
     */
    private makeLeafNodeConnect(root:TransferNode<T>,controllerp:T)
    {
        // 叶子节点之间建立连接
        const allleafNode:TransferNode<T>[]=[];
        this.getLeafChildren(root,allleafNode);
        const sortNodes = _.sortBy(allleafNode,e=>PositionHelper.Distance( e.pos,controllerp));
        while(sortNodes.length>0)
        {
            const upnode = sortNodes[0];
            for(let i=1;i<sortNodes.length;i++)
            {
                if(PositionHelper.Distance( sortNodes[i].pos,upnode.pos) ==1)
                {
                   
                     sortNodes[i].nextNode = upnode;
                }
            }
            sortNodes.splice(0,1);
        }
    }

    private findChildNode(parentnode:TransferNode<T>,visited:Set<number>,filter:IPosFilter<T>,childlimit=8):TransferNode<T>[]
    {
         
        const parent = parentnode.pos;
        const xs = [parent.x - 1,  parent.x + 1];
        const ys = [parent.y - 1,  parent.y + 1];
        const childrenpos:TransferNode<T>[]=[];
        for(let nx = xs[0];nx<=xs[1];nx++)
        {
            for(let ny = ys[0];ny<=ys[1];ny++)
            {
               
                if (  (nx<50 && nx>=0) && (ny<50 && ny>=0) && filter({x:nx,y:ny,roomName:parent.roomName} as T))
                {
                    if(visited.has(nx+ny*50))
                    {
                        continue;
                    }

                    const childNode = new TransferNode<T>({x:nx,y:ny,roomName:parent.roomName} as T,parentnode);
                    
                    this.workPositon[childNode.posKey]=childNode;
                    childrenpos.push(childNode);
                }
                if(childrenpos.length>=childlimit)
                {
                    parentnode.addChild(childrenpos);
                    return childrenpos;
                }
            }
        }
 
        parentnode.addChild(childrenpos);
        return childrenpos;
    }

    public balance(context:INodeContext<T>)
    {
        this.moveAction=[];
        this.moveToAction=[];
        for(const e of this._treeRoot)
        {
            this.initState(e,context);
        }
        
        // 平衡，各个位置的爬.从根节点开始
        for(const e of this._treeRoot)
        {
            if(e.state)
            {
                this.balanceTree(e);
            }
            
        }
       
        const ret ={move:this.moveAction,moveto:this.moveToAction};
      
        return ret;
    }

    public getWorkSlot(pos:IRoomPosition)
    {
        return this.workPositon[pos.y*50+pos.x];
    }
    public get slotCount()
    {
        return Object.keys(this.workPositon).length;
    }
    public get workSlots()
    {
        return this.workPositon;
    }
    private initState(node:TransferNode<T>,context:INodeContext<T>)
    {
        if(context.getObject( node.posKey))
        {
            node.state=1;
        }
        else
        {
            node.state=0;
        }
        for(const e of node.childnodes)
        {
            this.initState(e,context);
        }
    }
    private getChildren(root:TransferNode<T>,out:TransferNode<T>[])
    {
        for(const e of root.childnodes)
        {
            out.push(e);
            this.getChildren(e,out);
        }
    }
    private getLeafChildren(root:TransferNode<T>,out:TransferNode<T>[])
    {
        if(root.childnodes.length ==0)
        {
            out.push(root);
        }
        else
        {
            for(const e of root.childnodes)
            {
                this.getLeafChildren(e,out);
            }
        }
    }
    public getChildrenSlots(pos:T)
    {
         return this.rootChildrenPositon[PositionHelper.to1D(pos)];
    }
    private balanceTree(node:TransferNode<T>)
    {
        // 平衡，各个位置的爬.从根节点开始,逐级往下传递。
        /*
          从子节点借数据
        */
        if(node.parentNode)
        {
            if(node.childnodes.length>0)
            {
                if(this.isExist(node)) 
                {
                    // 本节点有内容,直接去找子节点
                    for(const e of node.childnodes)
                    {
                        this.balanceTree(e);
                    }
                }   
                else
                {
                    // 本节点为空
                    for(const e of node.childnodes)
                    {
                        if(this.isExist(e)&& !this.isExist(node))
                        {
                            this.moveUp(e as Required< TransferNode<T>>);
                        }
                        this.balanceTree(e);
                    }
                }
            }
            else
            {
                    // 叶子节点
                if(this.isExist(node)) 
                {
                    // 有就不管.
                    if(node.nextNode && !this.isExist(node.nextNode ))
                    {
                        this.movePre(node as Required< TransferNode<T>>);
                    }
                }
                else
                {
                    // 没有就从外部借,或者判断相邻的叶子
                    this.peek(node);
                   
                }
            }
        }
        else
        {
                // 是根节点,根节点是不可移动的
                for(const e of node.childnodes)
                {
                    this.balanceTree(e);
                }
        }
        
    }
    // 判断这个位置是否存在爬
    private isExist(node:TransferNode<T>)
    {
        return node.state
    }

    // 节点上移
    private moveUp(node:Required< TransferNode<T>>)
    {
        node.parentNode.state=1;
        node.state=0;
        this.moveAction.push({type:"move",From:node.pos,To:node.parentNode.pos})
    }

      // 节点上移
    private movePre(node:Required< TransferNode<T>>)
    {
        node.nextNode.state=1;
        node.state=0;
        this.moveAction.push({type:"move",From:node.pos,To:node.nextNode.pos})
    }
    private peek(node:TransferNode<T>)
    {
        this.moveToAction.push({type:"moveto",To:node.pos})
    }
    public print()
    {
        console.log(`------------分割线-------------`);
        for(const e of this._treeRoot)
        {
            this.printNode(e);
        }
       
    }
  
    private printNode(parent:TransferNode,deep:number=0)
    {
        let tab="\t";
        for(let i=0;i<deep;i++)
        {
            tab+="\t";
        }
        if(parent.nextNode)
        {
            console.log(`${tab}[${deep}]:<${parent.state}> ${parent.pos.x}_${parent.pos.y} ${parent.childnodes.length>0?"N":"Y"} --------> ${parent.nextNode.pos.x}_${parent.nextNode.pos.y} `);
        }
        else
        {
            console.log(`${tab}[${deep}]:<${parent.state}> ${parent.pos.x}_${parent.pos.y} ${parent.childnodes.length>0?"N":"Y"}  `);
        }
     
        for(const child of parent.childnodes)
        {
            this.printNode(child,deep+1);
        }
    }

    public visual()
    {
        for(const e of this._treeRoot)
        {
            this.visualNode(e);
        }
    }

    private visualNode(parent:TransferNode,deep:number=0)
    {
       
        const visual = Game.rooms[parent.pos.roomName].visual;
        if(parent.parentNode)
        {
            if(parent.childnodes.length)
            {
                // 中间节点
                visual.text(`X`, parent.pos.x, parent.pos.y, {color: "blue", font: 0.5});
            }
            else 
            {
                // 叶子
                visual.text(`L`, parent.pos.x, parent.pos.y, {color: "blue", font: 0.5});
            }
            
        }
        else 
        {
            // 根
            visual.text(`口`, parent.pos.x, parent.pos.y, {color: "blue", font: 0.5});
        }
        
        if(parent.nextNode)
        {
            this.visualLine(visual,parent.pos, parent.nextNode.pos,"red");
            // console.log(`${tab}[${deep}]:<${parent.state}> ${parent.pos.x}_${parent.pos.y} ${parent.childnodes.length>0?"N":"Y"} --------> ${parent.nextNode.pos.x}_${parent.nextNode.pos.y} `);
        }
        else
        {
            visual.circle(parent.pos.x,parent.pos.y,  { radius:0.1});
            // console.log(`${tab}[${deep}]:<${parent.state}> ${parent.pos.x}_${parent.pos.y} ${parent.childnodes.length>0?"N":"Y"}  `);
        }
     
        for(const child of parent.childnodes)
        {
            this.visualLine(visual,parent.pos, child.pos,"green");
            this.visualNode(child,deep+1);
        }
    }
    private visualLine(visual:RoomVisual,a:IRoomPosition,b:IRoomPosition,color:string)
    {
        visual.line(a.x,a.y,b.x,b.y, {color: color});
    }
}
